#include "messagetextedit.h"
#include <QDebug>
#include <QMessageBox>

// 构造函数，初始化 MessageTextEdit 对象
MessageTextEdit::MessageTextEdit(QWidget *parent)
    : QTextEdit(parent)
{
    // 设置文本编辑框的最大高度为 60 像素
    this->setMaximumHeight(60);

    // 注释掉的代码，可用于连接文本改变信号到 textEditChanged 槽函数
    // connect(this,SIGNAL(textChanged()),this,SLOT(textEditChanged()));
}

// 析构函数，目前为空，可用于释放对象占用的资源
MessageTextEdit::~MessageTextEdit()
{

}

// 获取消息列表，将文本编辑框中的消息整理成消息列表
QVector<MsgInfo> MessageTextEdit::getMsgList()
{
    // 清空存储获取到的消息列表
    mGetMsgList.clear();

    // 获取文本编辑框中的纯文本内容
    QString doc = this->document()->toPlainText();
    // 用于临时存储文本信息
    QString text = "";
    // 用于记录消息列表的索引
    int indexUrl = 0;
    // 获取消息列表的大小
    int count = mMsgList.size();

    // 遍历文本内容
    for(int index = 0; index < doc.size(); index++)
    {
        // 如果遇到对象替换字符
        if(doc[index] == QChar::ObjectReplacementCharacter)
        {
            // 如果临时文本不为空
            if(!text.isEmpty())
            {
                // 创建一个空的 QPixmap
                QPixmap pix;
                // 将临时文本作为文本消息插入到获取的消息列表中
                insertMsgList(mGetMsgList, "text", text, pix);
                // 清空临时文本
                text.clear();
            }
            // 遍历消息列表
            while(indexUrl < count)
            {
                // 获取当前索引的消息
                MsgInfo msg = mMsgList[indexUrl];
                // 如果文本编辑框的 HTML 内容包含该消息的内容
                if(this->document()->toHtml().contains(msg.content, Qt::CaseSensitive))
                {
                    // 索引加 1
                    indexUrl++;
                    // 将该消息添加到获取的消息列表中
                    mGetMsgList.append(msg);
                    break;
                }
                // 索引加 1
                indexUrl++;
            }
        }
        else
        {
            // 如果不是对象替换字符，将字符添加到临时文本中
            text.append(doc[index]);
        }
    }
    // 如果遍历结束后临时文本不为空
    if(!text.isEmpty())
    {
        // 创建一个空的 QPixmap
        QPixmap pix;
        // 将临时文本作为文本消息插入到获取的消息列表中
        insertMsgList(mGetMsgList, "text", text, pix);
        // 清空临时文本
        text.clear();
    }
    // 清空存储的消息列表
    mMsgList.clear();
    // 清空文本编辑框
    this->clear();
    // 返回获取的消息列表
    return mGetMsgList;
}

// 处理拖拽进入事件
void MessageTextEdit::dragEnterEvent(QDragEnterEvent *event)
{
    // 如果拖拽源是自身，忽略该事件
    if(event->source() == this)
        event->ignore();
    else
        // 否则接受该事件
        event->accept();
}

// 处理拖拽放下事件
void MessageTextEdit::dropEvent(QDropEvent *event)
{
    // 从 MIME 数据中插入文件
    insertFromMimeData(event->mimeData());
    // 接受该事件
    event->accept();
}

// 处理按键按下事件
void MessageTextEdit::keyPressEvent(QKeyEvent *e)
{
    // 如果按下的是 Enter 或 Return 键，且没有按下 Shift 键
    if((e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) && !(e->modifiers() & Qt::ShiftModifier))
    {
        // 发出发送信号
        emit send();
        return;
    }
    // 调用基类的按键按下事件处理函数
    QTextEdit::keyPressEvent(e);
}

// 根据文件 URL 插入文件
void MessageTextEdit::insertFileFromUrl(const QStringList &urls)
{
    // 如果 URL 列表为空，直接返回
    if(urls.isEmpty())
        return;

    // 遍历 URL 列表
    foreach (QString url, urls) {
        // 如果是图片文件
        if(isImage(url))
            // 插入图片
            insertImages(url);
        else
            // 插入文本文件
            insertTextFile(url);
    }
}

// 插入图片文件
void MessageTextEdit::insertImages(const QString &url)
{
    // 加载图片
    QImage image(url);
    // 按比例缩放图片，如果图片宽度大于 120 或高度大于 80
    if(image.width() > 120 || image.height() > 80)
    {
        if(image.width() > image.height())
        {
            // 按宽度缩放
            image = image.scaledToWidth(120, Qt::SmoothTransformation);
        }
        else
        {
            // 按高度缩放
            image = image.scaledToHeight(80, Qt::SmoothTransformation);
        }
    }
    // 获取文本光标
    QTextCursor cursor = this->textCursor();
    // 在光标位置插入图片
    cursor.insertImage(image, url);
    // 将图片消息插入到消息列表中
    insertMsgList(mMsgList, "image", url, QPixmap::fromImage(image));
}

// 插入文本文件
void MessageTextEdit::insertTextFile(const QString &url)
{
    // 获取文件信息
    QFileInfo fileInfo(url);
    // 如果是文件夹
    if(fileInfo.isDir())
    {
        // 弹出提示框，只允许拖拽单个文件
        QMessageBox::information(this, "提示", "只允许拖拽单个文件!");
        return;
    }
    // 如果文件大小大于 100MB
    if(fileInfo.size() > 100 * 1024 * 1024)
    {
        // 弹出提示框，发送的文件大小不能大于 100M
        QMessageBox::information(this, "提示", "发送的文件大小不能大于 100M");
        return;
    }
    // 获取文件图标
    QPixmap pix = getFileIconPixmap(url);
    // 获取文本光标
    QTextCursor cursor = this->textCursor();
    // 在光标位置插入文件图标
    cursor.insertImage(pix.toImage(), url);
    // 将文件消息插入到消息列表中
    insertMsgList(mMsgList, "file", url, pix);
}

// 判断是否可以从 MIME 数据中插入内容
bool MessageTextEdit::canInsertFromMimeData(const QMimeData *source) const
{
    // 调用基类的方法判断
    return QTextEdit::canInsertFromMimeData(source);
}

// 从 MIME 数据中插入内容
void MessageTextEdit::insertFromMimeData(const QMimeData *source)
{
    // 从文本中提取 URL 列表
    QStringList urls = getUrl(source->text());
    // 如果 URL 列表为空，直接返回
    if(urls.isEmpty())
        return;
    // 遍历 URL 列表
    foreach (QString url, urls) {
        // 如果是图片文件
        if(isImage(url))
            // 插入图片
            insertImages(url);
        else
            // 插入文本文件
            insertTextFile(url);
    }
}

// 判断文件是否为图片
bool MessageTextEdit::isImage(QString url)
{
    // 定义图片格式列表
    QString imageFormat = "bmp,jpg,png,tif,gif,pcx,tga,exif,fpx,svg,psd,cdr,pcd,dxf,ufo,eps,ai,raw,wmf,webp";
    // 将图片格式列表分割成字符串列表
    QStringList imageFormatList = imageFormat.split(",");
    // 获取文件信息
    QFileInfo fileInfo(url);
    // 获取文件后缀
    QString suffix = fileInfo.suffix();
    // 如果后缀在图片格式列表中
    if(imageFormatList.contains(suffix, Qt::CaseInsensitive)) {
        return true;
    }
    return false;
}

// 将消息插入到消息列表中
void MessageTextEdit::insertMsgList(QVector<MsgInfo> &list, QString flag, QString text, QPixmap pix)
{
    // 创建一个消息对象
    MsgInfo msg;
    // 设置消息标志
    msg.msgFlag = flag;
    // 设置消息内容
    msg.content = text;
    // 设置消息图片
    msg.pixmap = pix;
    // 将消息添加到消息列表中
    list.append(msg);
}

// 从文本中提取 URL 列表
QStringList MessageTextEdit::getUrl(QString text)
{
    // 存储 URL 列表
    QStringList urls;
    // 如果文本为空，直接返回空列表
    if(text.isEmpty()) return urls;
    // 将文本按换行符分割成字符串列表
    QStringList list = text.split("\n");
    // 遍历字符串列表
    foreach (QString url, list) {
        // 如果字符串不为空
        if(!url.isEmpty()) {
            // 将字符串按 "///" 分割成字符串列表
            QStringList str = url.split("///");
            // 如果分割后的列表长度大于等于 2
            if(str.size() >= 2)
                // 将第二个元素添加到 URL 列表中
                urls.append(str.at(1));
        }
    }
    return urls;
}

// 获取文件图标及大小信息，并转化成图片
QPixmap MessageTextEdit::getFileIconPixmap(const QString &url)
{
    // 创建文件图标提供者
    QFileIconProvider provder;
    // 获取文件信息
    QFileInfo fileinfo(url);
    // 获取文件图标
    QIcon icon = provder.icon(fileinfo);
    // 获取文件大小的字符串表示
    QString strFileSize = getFileSize(fileinfo.size());
    // 输出文件大小到调试窗口
    //qDebug() << "FileSize=" << fileinfo.size();

    // 设置字体
    QFont font(QString("宋体"), 10, QFont::Normal, false);
    // 获取字体度量信息
    QFontMetrics fontMetrics(font);
    // 获取文件名的文本大小
    QSize textSize = fontMetrics.size(Qt::TextSingleLine, fileinfo.fileName());
    // 获取文件大小字符串的文本大小
    QSize FileSize = fontMetrics.size(Qt::TextSingleLine, strFileSize);
    // 获取文件名和文件大小字符串中宽度较大的值
    int maxWidth = textSize.width() > FileSize.width() ? textSize.width() : FileSize.width();
    // 创建一个指定大小的 QPixmap
    QPixmap pix(50 + maxWidth + 10, 50);
    // 填充 QPixmap 为透明
    pix.fill();

    // 创建 QPainter 对象
    QPainter painter;
    // 开始绘制
    painter.begin(&pix);
    // 绘制文件图标
    QRect rect(0, 0, 50, 50);
    painter.drawPixmap(rect, icon.pixmap(40, 40));
    // 设置画笔颜色为黑色
    painter.setPen(Qt::black);
    // 绘制文件名
    QRect rectText(50 + 10, 3, textSize.width(), textSize.height());
    painter.drawText(rectText, fileinfo.fileName());
    // 绘制文件大小
    QRect rectFile(50 + 10, textSize.height() + 5, FileSize.width(), FileSize.height());
    painter.drawText(rectFile, strFileSize);
    // 结束绘制
    painter.end();
    return pix;
}

// 获取文件大小的字符串表示
QString MessageTextEdit::getFileSize(qint64 size)
{
    // 存储文件大小单位
    QString Unit;
    // 存储文件大小数值
    double num;
    // 根据文件大小选择合适的单位
    if(size < 1024) {
        num = size;
        Unit = "B";
    }
    else if(size < 1024 * 1024) {
        num = size / 1024.0;
        Unit = "KB";
    }
    else if(size < 1024 * 1024 * 1024) {
        num = size / 1024.0 / 1024.0;
        Unit = "MB";
    }
    else {
        num = size / 1024.0 / 1024.0 / 1024.0;
        Unit = "GB";
    }
    // 返回文件大小的字符串表示
    return QString::number(num, 'f', 2) + " " + Unit;
}

// 文本编辑框内容改变时的槽函数
void MessageTextEdit::textEditChanged()
{
    // 注释掉的代码，可用于输出文本改变的调试信息
    //qDebug() << "text changed!" << endl;
}
